package gr.uoa.di.thanos.botcraft.game;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * This class represents a 3D vector.
 * @author thanos.papapetrou@gmail.com
 *
 */
public class Vector {
	private static final Pattern PATTERN = Pattern.compile("^\\s*\\((\\S+)\\s*,\\s*(\\S+)\\s*,\\s*(\\S+)\\)\\s*$");
	
	private final float x;
	private final float y;
	private final float z;
	
	/**
	 * Construct a new vector.
	 * @param x the x coordinate
	 * @param y the y coordinate
	 * @param z the z coordinate
	 */
	public Vector(final float x, final float y, final float z) {
		this.x = x;
		this.y = y;
		this.z = z;
	}
	
	/**
	 * Construct a new vector by parsing a string.
	 * @param vector the string to parse
	 */
	public Vector(final String vector) {
		final Matcher matcher = PATTERN.matcher(vector);
		if (!matcher.matches())
			throw new IllegalArgumentException("Invalid vector");
		x = Float.parseFloat(matcher.group(1));
		y = Float.parseFloat(matcher.group(2));
		z = Float.parseFloat(matcher.group(3));
	}
	
	/**
	 * Get the x coordinate.
	 * @return the x coordinate
	 */
	public float getX() {
		return x;
	}
	
	/**
	 * Get the y coordinate.
	 * @return the y coordinate
	 */
	public float getY() {
		return y;
	}

	/**
	 * Get the z coordinate.
	 * @return the z coordinate
	 */
	public float getZ() {
		return z;
	}
	
	/**
	 * Add a vector to this vector.
	 * @param vector the vector to add
	 * @return the resulting vector
	 */
	public Vector add(final Vector vector) {
		return new Vector(x + vector.x, y + vector.y, z + vector.z);
	}
	
	/**
	 * Multiply this vector with a scalar number.
	 * @param a the scalar to multiply with
	 * @return the resulting vector
	 */
	public Vector multiply(final float a) {
		return new Vector(a * x, a * y, a * z);
	}
	
	/**
	 * Multiply this vector with another vector.
	 * @param vector the vector to multiply with
	 * @return the resulting vector
	 */
	public Vector multiply(final Vector vector) {
		return new Vector(y * vector.z - z * vector.y, z * vector.x - x * vector.z, x * vector.y - y * vector.x);
	}
	
	/**
	 * Calculate the length of this vector.
	 * @return the length of this vector
	 */
	public float length() {
		return Double.valueOf(Math.sqrt(x * x + y * y + z * z)).floatValue();
	}
	
	/**
	 * Normalize this vector.
	 * @return a vector having the same direction with this vector but a length of 1
	 */
	public Vector normalize() {
		return multiply(1.0f / length());
	}
	
	@Override
	public boolean equals(final java.lang.Object object) {
		return (object instanceof Vector) && (x == ((Vector) object).x) && (y == ((Vector) object).y) && (z == ((Vector) object).z);
	}
	
	@Override
	public int hashCode() {
		return Float.floatToIntBits(x) + Float.floatToIntBits(y) + Float.floatToIntBits(z);
	}
	
	@Override
	public String toString() {
		return "(" + x + ", " + y + ", " + z + ")";
	}
}
